package com.tools.web.email;

import com.tools.common.container.MapEnum;
import com.tools.common.container.OwnRows;
import com.tools.common.io.CharsetEnum;
import com.tools.common.object.Note;
import com.tools.web.http.UploadFile;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;

/**
 * 邮件构造实体
 * 包含主题、内容、抄送人、附件等等信息
 * */
@Note("邮件构造实体，包含主题、内容、抄送人、附件等等信息")
public final class MailBuilder {

    @Note("邮件标题")
    private String subject;

    @Note("邮件内容，支持 HTML 模板语法")
    private String content;

    @Note("接收方和抄送方的邮箱实体")
    private LinkedHashSet<MailUser> receiverMails;

    @Note("如果添加附件，则附件实体存放在此")
    private List<UploadFile> attachments;

    @Note("邮件的字符集编码，默认为 UTF-8")
    private CharsetEnum encoder = CharsetEnum.UTF_8;

    @Note("判断该类的邮件信息是否是回复的，还是新邮件。true 为回复，false 为新邮件。默认为新邮件")
    private boolean isReply;

    @Note("这个属性用于回复邮件时的，判断新的 subject 是覆盖 【Re: xxx】 还是拼接在其后面。" +
            "true 是覆盖，false 是拼接。默认为 false 拼接。")
    private boolean replaceSubject;

    public MailBuilder() {}

    @Note("静态工厂创建实例")
    public static MailBuilder of() {
        return new MailBuilder();
    }

    /* **********************************************************************************
     *
     *          Getter / Setter
     *
     * *********************************************************************************
     * */

    public String getSubject() {
        return subject;
    }

    public void setSubject(String subject) {
        this.subject = subject;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public LinkedHashSet<MailUser> getReceiverMails() {
        return receiverMails;
    }

    public void setReceiverMails(final LinkedHashSet<MailUser> receiverMails) {
        if(receiverMails == null || receiverMails.isEmpty()) throw new NullPointerException("你至少添加一个邮件接收者");
        this.receiverMails = receiverMails;
    }

    public List<UploadFile> getAttachments() {
        return attachments;
    }

    public void  setAttachments(List<UploadFile> attachments) {
        this.attachments = attachments;
    }

    public CharsetEnum getEncoder() {
        return encoder;
    }

    public void setEncoder(CharsetEnum encoder) {
        if(encoder == null) throw new NullPointerException("不知道 null 是什么字符集编码");
        this.encoder = encoder;
    }

    public boolean getIsReply() {
        return isReply;
    }

    public void setIsReply(boolean isReply) {
        this.isReply = isReply;
    }

    public boolean isReplaceSubject() {
        return replaceSubject;
    }

    public void setReplaceSubject(boolean replaceSubject) {
        this.replaceSubject = replaceSubject;
    }

    @Override
    public String toString() {
        return "MailBuilder{" +
                "isReply=" + isReply +
                ", replaceSubject=" + replaceSubject +
                ", encoder=" + encoder +
                ", receiverMails=" + receiverMails +
                ", attachments=" + attachments +
                ", subject='" + subject + '\'' +
                ", content='" + content + '\'' +
                '}';
    }

    /* **********************************************************************************
     *
     *          链式方法
     *
     * *********************************************************************************
     * */

    public MailBuilder subject(String subject) {
        this.setSubject(subject);
        return this;
    }

    public MailBuilder content(String content) {
        this.setContent(content);
        return this;
    }

    public MailBuilder encoder(CharsetEnum encoder) {
        this.setEncoder(encoder);
        return this;
    }

    public MailBuilder receiverMails(LinkedHashSet<MailUser> receiverUsers) {
        this.setReceiverMails(receiverUsers);
        return this;
    }

    public MailBuilder attachments(List<UploadFile> attachments) {
        this.setAttachments(attachments);
        return this;
    }

    public MailBuilder replaceSubject(boolean replaceSubject) {
        this.setReplaceSubject(replaceSubject);
        return this;
    }

    @Note("使用默认的 Session 和 MailSource 对象构造邮件并发送。" +
            "使用该方法前必须确保，外部配置文件必须有默认配置，否则会抛异常")
    public void send() {
        MailKit.send(this);
    }

    /* **********************************************************************************
     *
     *          邮件接收者 - 自定义方法
     *
     * *********************************************************************************
     * */

    public MailBuilder addUser(MailUser mailUser) {
        private_mailUserNotNull(mailUser);
        private_lazyInitReceivers(1);
        this.receiverMails.add(mailUser);
        return this;
    }

    public MailBuilder addUsers(MailUser... mailUsers) {
        if(mailUsers == null || mailUsers.length == 0) return this;
        private_lazyInitReceivers(mailUsers.length);
        for(MailUser mailUser : mailUsers) {
            private_mailUserNotNull(mailUser);
            this.receiverMails.add(mailUser);
        }
        return this;
    }

    public MailBuilder addUsers(Collection<MailUser> mailUsers) {
        if(mailUsers == null || mailUsers.isEmpty()) return this;
        private_lazyInitReceivers(mailUsers.size());
        for(MailUser mailUser : mailUsers) {
            private_mailUserNotNull(mailUser);
            this.receiverMails.add(mailUser);
        }
        return this;
    }

    public MailBuilder addUsers(OwnRows<MailUser> mailUsers) {
        if(mailUsers != null && !mailUsers.isEmpty()) {
            private_lazyInitReceivers(mailUsers.size());
            for(MailUser mailUser : mailUsers) {
                private_mailUserNotNull(mailUser);
                this.receiverMails.add(mailUser);
            }
        }
        return this;
    }


    public MailBuilder removeUser(MailUser mailUser) {
        if(receiverMails == null || receiverMails.isEmpty()) return this;
        this.receiverMails.remove(mailUser);
        return this;
    }

    public MailBuilder removeUsers(MailUser... mailUsers) {
        if(mailUsers == null || mailUsers.length == 0) return this;
        if(receiverMails == null || receiverMails.isEmpty()) return this;
        for (MailUser mailUser : mailUsers) this.receiverMails.remove(mailUser);
        return this;
    }

    public MailBuilder removeUsers(Iterable<MailUser> mailUsers) {
        if(mailUsers == null) return this;
        if(receiverMails == null || receiverMails.isEmpty()) return this;
        for (MailUser mailUser : mailUsers) this.receiverMails.remove(mailUser);
        return this;
    }

    public boolean containsUser(MailUser mailUser) {
        if(receiverMails == null || receiverMails.isEmpty()) return false;
        return this.receiverMails.contains(mailUser);
    }

    public int userSize() {
        return (receiverMails == null || receiverMails.isEmpty())
                ? 0
                : receiverMails.size();
    }

    /* **********************************************************************************
     *
     *          附件 - 自定义方法
     *
     * *********************************************************************************
     * */

    public MailBuilder addFile(UploadFile file) {
        private_attachmentNotNull(file);
        private_lazyLoadAttachment(1);
        this.attachments.add(file);
        return this;
    }


    public MailBuilder addFiles(UploadFile... attachments) {
        if(attachments == null || attachments.length == 0) return this;
        private_lazyLoadAttachment(attachments.length);
        for (UploadFile file : attachments) {
            private_attachmentNotNull(file);
            this.attachments.add(file);
        }
        return this;
    }

    public MailBuilder addFiles(Collection<UploadFile> attachments) {
        if(attachments == null || attachments.isEmpty()) return this;
        private_lazyLoadAttachment(attachments.size());
        for (UploadFile file : attachments) {
            private_attachmentNotNull(file);
            this.attachments.add(file);
        }
        return this;
    }

    public MailBuilder addFiles(OwnRows<UploadFile> attachments) {
        if(attachments != null && !attachments.isEmpty()) {
            private_lazyLoadAttachment(attachments.size());
            for (UploadFile file : attachments) {
                private_attachmentNotNull(file);
                this.attachments.add(file);
            }
        }
        return this;
    }


    public MailBuilder removeFile(UploadFile attachment) {
        if(attachment == null) return this;
        if(attachments == null || attachments.isEmpty()) return this;
        this.attachments.remove(attachment);
        return this;
    }

    public MailBuilder removeFile(int index) {
        if(attachments == null || attachments.isEmpty()) return this;
        if(index < 0 || index >= attachments.size()) return this;
        this.attachments.remove(index);
        return this;
    }


    public MailBuilder removeFiles(UploadFile... attachments) {
        if(attachments == null || attachments.length == 0) return this;
        if(this.attachments == null || this.attachments.isEmpty()) return this;
        for (UploadFile file : attachments) this.attachments.remove(file);
        return this;
    }

    public MailBuilder removeFiles(Iterable<UploadFile> attachments) {
        if(attachments == null) return this;
        if(this.attachments == null || this.attachments.isEmpty()) return this;
        for (UploadFile file : attachments) this.attachments.remove(file);
        return this;
    }

    public boolean containsFile(UploadFile attachment) {
        return this.attachments != null && this.attachments.contains(attachment);
    }

    public int fileSize() {
        return (this.attachments == null) ? 0 : this.attachments.size();
    }

    /* **********************************************************************************
     *
     *          私有逻辑
     *
     * *********************************************************************************
     * */

    @Note("懒加载接收者邮箱的容器，线程不安全操作，切记不要单例对象多线程做增删")
    private void private_lazyInitReceivers(int initSize) {
        if(receiverMails == null) {
            this.receiverMails = new LinkedHashSet<>(MapEnum.calcInitSize(initSize));
        }
    }

    @Note("懒加载附件列表，线程不安全操作，切记不要单例对象多线程做增删")
    private void private_lazyLoadAttachment(int initSize) {
        if(attachments == null) {
            attachments = new ArrayList<>(initSize);
        }
    }

    @Note("邮件接收者包装对象不能为 null")
    private static void private_mailUserNotNull(MailUser mailUser) {
        if(mailUser == null) throw new NullPointerException("不能添加 null 的邮件接收者");
    }


    @Note("邮件附件对象不能为 null")
    private static void private_attachmentNotNull(UploadFile file) {
        if(file == null) throw new NullPointerException("不能添加 null 的附件");
    }



}
